package org.orbroker

import java.sql._
import java.sql.ResultSet._

private[orbroker] trait QueryStatement extends SQLStatement with ResultSetProducer {

  private def preparedQuery[T](
    token: Token[T], session: Session, parsed: ParsedSQL,
    parms: Map[String, Any], receiver: T ⇒ Boolean): (String, Seq[Any]) = {
    val ps = parsed.prepareQuery(session.connection)
    try {
      setFeatures(ps, session)
      val values = setParms(token, ps, parsed.parmDefs, parms)
      val rs = ps.executeQuery()
      mapResult(token.extractor, rs, receiver)
      (parsed.sql, values)
    } finally {
      import JdbcCloser._
      checkWarningsAndClose(ps, callback)
    }
  }

  private def unpreparedQuery[T](
    token: Token[T], session: Session,
    parsed: ParsedSQL, receiver: T ⇒ Boolean) {
    val stm = parsed.createStatement(session.connection)
    try {
      setFeatures(stm, session)
      val rs = stm.executeQuery(parsed.sql)
      mapResult(token.extractor, rs, receiver)
    } finally {
      import JdbcCloser._
      checkWarningsAndClose(stm, callback)
    }
  }

  def query[T](
    token: Token[T], session: Session,
    parms: Map[String, Any], receiver: T ⇒ Boolean): (String, Seq[Any]) = {
    val parsed = statement(parms)
    if (!session.alwaysPrepare && parsed.parmDefs.isEmpty) {
      unpreparedQuery(token, session, parsed, receiver)
      (parsed.sql, List.empty)
    } else {
      preparedQuery(token, session, parsed, parms, receiver)
    }
  }

}
